/*         ______________________________________
  ________|                                      |_______
  \       |             JarvisWidget             |      /
   \      |      Copyright © 2014 MyOrange       |     /
   /      |______________________________________|     \
  /__________)                                (_________\

 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * =======================================================================
 * JarvisWidget is FULLY owned and LICENSED by MYORANGE INC.
 * This script may NOT be RESOLD or REDISTRUBUTED on its own under any
 * circumstances, and is only to be used with this purchased
 * copy of SmartAdmin Template.
 * =======================================================================
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * =======================================================================
 * original filename: jarvis.widget.js
 * filesize: 56.7 KB (58,158 bytes)
 * author: Sunny (@bootstraphunt)
 * email: support@myorange.ca
 */

(function($, window, document, undefined) {

    //"use strict"; 

    var pluginName = "jarvisWidgets";

    /**
     * Check for touch support and set right click events.
     **/
    var clickEvent =
        (("ontouchstart" in window) || window.DocumentTouch && document instanceof DocumentTouch
                ? "clickEvent"
                : "click") +
            "." +
            pluginName;

    function Plugin(element, options) {
        /**
         * Variables.
         **/
        this.obj = $(element);
        this.o = $.extend({}, $.fn[pluginName].defaults, options);
        this.objId = this.obj.attr("id");
        this.pwCtrls = ".jarviswidget-ctrls";
        this.widget = this.obj.find(this.o.widgets);
        this.toggleClass = this.o.toggleClass.split("|");
        this.editClass = this.o.editClass.split("|");
        this.fullscreenClass = this.o.fullscreenClass.split("|");
        this.customClass = this.o.customClass.split("|");
        this.storage = { enabled: this.o.localStorage };
        this.initialized = false;

        this.init();
    }

    Plugin.prototype = {

        /**
         * Function for the indicator image.
         *
         * @param:
         **/
        _runLoaderWidget: function(elm) {
            var self = this;
            if (self.o.indicator === true) {
                elm.parents(self.o.widgets)
                    .find(".jarviswidget-loader:first")
                    .stop(true, true)
                    .fadeIn(100)
                    .delay(self.o.indicatorTime)
                    .fadeOut(100);
            }
        },

        /**
         * Create a fixed timestamp.
         *
         * @param: t | date | Current date.
         **/
        _getPastTimestamp: function(t) {

            var self = this;

            var da = new Date(t);


            /**
             * Get and set the date and time.
             **/
            var tsMonth = da.getMonth() + 1;
            // index based
            var tsDay = da.getDate();
            var tsYear = da.getFullYear();
            var tsHours = da.getHours();
            var tsMinutes = da.getMinutes();
            var tsSeconds = da.getUTCSeconds();

            /**
             * Checking for one digit values, if so add an zero.
             **/
            if (tsMonth < 10) {
                tsMonth = "0" + tsMonth;
            }
            if (tsDay < 10) {
                tsDay = "0" + tsDay;
            }
            if (tsHours < 10) {
                tsHours = "0" + tsHours;
            }
            if (tsMinutes < 10) {
                tsMinutes = "0" + tsMinutes;
            }
            if (tsSeconds < 10) {
                tsSeconds = "0" + tsSeconds;
            }

            /**
             * The output, how you want it.
             **/
            var format = self.o.timestampFormat.replace(/%d%/g, tsDay)
                .replace(/%m%/g, tsMonth)
                .replace(/%y%/g, tsYear)
                .replace(/%h%/g, tsHours)
                .replace(/%i%/g, tsMinutes)
                .replace(/%s%/g, tsSeconds);

            return format;
        },

        /**
         * AJAX load File, which get and shows the .
         *
         * @param: awidget | object  | The widget.
         * @param: file    | file    | The file thats beeing loaded.
         * @param: loader  | object  | The widget.
         **/
        _loadAjaxFile: function(awidget, file, loader) {

            var self = this;

            awidget.find(".widget-body")
                .load(file,
                    function(response, status, xhr) {

                        var $this = $(this);

                        /**
                         * If action runs into an error display an error msg.
                         **/
                        if (status == "error") {
                            $this.html('<h4 class="alert alert-danger">' +
                                self.o.labelError +
                                "<b> " +
                                xhr.status +
                                " " +
                                xhr.statusText +
                                "</b></h4>");
                        }

                        /**
                         * Run if there are no errors.
                         **/
                        if (status == "success") {

                            /**
                             * Show a timestamp.
                             **/
                            var aPalceholder = awidget.find(self.o.timestampPlaceholder);

                            if (aPalceholder.length) {

                                aPalceholder.html(self._getPastTimestamp(new Date()));
                            }

                            /**
                             * Run the callback function.
                             **/
                            if (typeof self.o.afterLoad == "function") {
                                self.o.afterLoad.call(this, awidget);
                            }
                        }

                        self = null;
                    });

            /**
             * Run function for the indicator image.
             **/
            this._runLoaderWidget(loader);

        },

        _loadKeys: function() {

            var self = this;

            //*****************************************************************//
            /////////////////////////// SET/GET KEYS ////////////////////////////
            //*****************************************************************//

            // TODO : Push state does not work on IE9, try to find a way to detect IE and use a seperate filter

            if (self.o.ajaxnav === true) {
                var widget_url = location.hash.replace(/^#/, "");
                self.storage.keySettings = "Plugin_settings_" + widget_url + "_" + self.objId;
                self.storage.keyPosition = "Plugin_position_" + widget_url + "_" + self.objId;
            } else if (self.initialized === false) {
                var widget_url = self.o.pageKey || location.pathname;
                self.storage.keySettings = "jarvisWidgets_settings_" + widget_url + "_" + self.objId;
                self.storage.keyPosition = "jarvisWidgets_position_" + widget_url + "_" + self.objId;
            }

        },

        /**
         * Save all settings to the localStorage.
         *
         * @param:
         **/
        _saveSettingsWidget: function() {

            var self = this;
            var storage = self.storage;

            self._loadKeys();

            var storeSettings = self.obj.find(self.o.widgets)
                .map(function() {
                    var storeSettingsStr = {};
                    storeSettingsStr.id = $(this)
                        .attr("id");
                    storeSettingsStr.style = $(this)
                        .attr("data-widget-attstyle");
                    storeSettingsStr.title = $(this)
                        .children("header")
                        .children("h2")
                        .text();
                    storeSettingsStr.hidden = ($(this)
                        .css("display") ==
                        "none"
                        ? 1
                        : 0);
                    storeSettingsStr.collapsed = ($(this)
                        .hasClass("jarviswidget-collapsed")
                        ? 1
                        : 0);
                    return storeSettingsStr;
                }).get();

            var storeSettingsObj = JSON.stringify({
                'widget': storeSettings
            });

            /* Place it in the storage(only if needed) */
            if (storage.enabled && storage.getKeySettings != storeSettingsObj) {
                localStorage.setItem(storage.keySettings, storeSettingsObj);
                storage.getKeySettings = storeSettingsObj;
            }

            /**
             * Run the callback function.
             **/

            if (typeof self.o.onSave == "function") {
                self.o.onSave.call(this, null, storeSettingsObj, storage.keySettings);
            }
        },

        /**
         * Save positions to the localStorage.
         *
         * @param:
         **/
        _savePositionWidget: function() {

            var self = this;
            var storage = self.storage;

            self._loadKeys();

            var mainArr = self.obj.find(self.o.grid + ".sortable-grid")
                .map(function() {
                    var subArr = $(this)
                        .children(self.o.widgets)
                        .map(function() {
                            return {
                                'id': $(this).attr("id")
                            };
                        }).get();
                    return {
                        'section': subArr
                    };
                }).get();

            var storePositionObj = JSON.stringify({
                'grid': mainArr
            });

            /* Place it in the storage(only if needed) */
            if (storage.enabled && storage.getKeyPosition != storePositionObj) {
                localStorage.setItem(storage.keyPosition, storePositionObj);
                storage.getKeyPosition = storePositionObj;
            }

            /**
             * Run the callback function.
             **/
            if (typeof self.o.onSave == "function") {
                self.o.onSave.call(this, storePositionObj, storage.keyPosition);
            }
        },

        /**
         * Code that we run at the start.
         *
         * @param:
         **/
        init: function() {

            var self = this;

            if (self.initialized) return;

            self._initStorage(self.storage);

            /**
             * Force users to use an id(it's needed for the local storage).
             **/
            if (!$("#" + self.objId)
                .length) {
                alert("It looks like your using a class instead of an ID, dont do that!");
            }

            /**
             * Add RTL support.
             **/
            if (self.o.rtl === true) {
                $("body")
                    .addClass("rtl");
            }

            /**
             * This will add an extra class that we use to store the
             * widgets in the right order.(savety)
             **/

            $(self.o.grid)
                .each(function() {
                    if ($(this)
                        .find(self.o.widgets)
                        .length) {
                        $(this)
                            .addClass("sortable-grid");
                    }
                });

            //*****************************************************************//
            //////////////////////// SET POSITION WIDGET ////////////////////////
            //*****************************************************************//

            /**
             * Run if data is present.
             **/
            if (self.storage.enabled && self.storage.getKeyPosition) {

                var jsonPosition = JSON.parse(self.storage.getKeyPosition);

                /**
                 * Loop the data, and put every widget on the right place.
                 **/
                for (var key in jsonPosition.grid) {
                    var changeOrder = self.obj.find(self.o.grid + ".sortable-grid")
                        .eq(key);
                    for (var key2 in jsonPosition.grid[key].section) {
                        changeOrder.append($("#" + jsonPosition.grid[key].section[key2].id));
                    }
                }

            }

            //*****************************************************************//
            /////////////////////// SET SETTINGS WIDGET /////////////////////////
            //*****************************************************************//

            /**
             * Run if data is present.
             **/
            if (self.storage.enabled && self.storage.getKeySettings) {

                var jsonSettings = JSON.parse(self.storage.getKeySettings);

                /**
                 * Loop the data and hide/show the widgets and set the inputs in
                 * panel to checked(if hidden) and add an indicator class to the div.
                 * Loop all labels and update the widget titles.
                 **/
                for (var key in jsonSettings.widget) {
                    var widgetId = $("#" + jsonSettings.widget[key].id);

                    /**
                     * Set a style(if present).
                     **/
                    if (jsonSettings.widget[key].style) {
                        //console.log("test");
                        widgetId.removeClassPrefix("jarviswidget-color-")
                            .addClass(jsonSettings.widget[key].style)
                            .attr("data-widget-attstyle", "" + jsonSettings.widget[key].style + "");
                    }

                    /**
                     * Hide/show widget.
                     **/
                    if (jsonSettings.widget[key].hidden == 1) {
                        widgetId.hide(1);
                    } else {
                        widgetId.show(1)
                            .removeAttr("data-widget-hidden");
                    }

                    /**
                     * Toggle content widget.
                     **/
                    if (jsonSettings.widget[key].collapsed == 1) {
                        widgetId.addClass("jarviswidget-collapsed")
                            .children("div")
                            .hide(1);
                    }

                    /**
                     * Update title widget (if needed).
                     **/
                    if (widgetId.children("header")
                        .children("h2")
                        .text() !=
                        jsonSettings.widget[key].title) {
                        widgetId.children("header")
                            .children("h2")
                            .text(jsonSettings.widget[key].title);
                    }
                }
            }

            //*****************************************************************//
            ////////////////////////// LOOP AL WIDGETS //////////////////////////
            //*****************************************************************//

            /**
             * This will add/edit/remove the settings to all widgets
             **/
            self.widget.each(function() {

                var tWidget = $(this),
                    thisHeader = $(this).children("header"),
                    customBtn,
                    deleteBtn,
                    editBtn,
                    fullscreenBtn,
                    widgetcolorBtn,
                    toggleBtn,
                    toggleSettings,
                    refreshBtn;

                /**
                 * Dont double wrap(check).
                 **/
                if (!thisHeader.parent()
                    .attr("role")) {

                    /**
                     * Hide the widget if the dataset 'widget-hidden' is set to true.
                     **/
                    if (tWidget.data("widget-hidden") === true) {

                        tWidget.hide();
                    }

                    /**
					 * Hide the content of the widget if the dataset
					 * 'widget-collapsed' is set to true.

					 **/
                    if (tWidget.data("widget-collapsed") === true) {
                        tWidget.addClass("jarviswidget-collapsed")
                            .children("div")
                            .hide();
                    }

                    /**
                     * Check for the dataset 'widget-icon' if so get the icon
                     * and attach it to the widget header.
                     * NOTE: MOVED THIS TO PHYSICAL for more control
                     **/
                    //if(tWidget.data('widget-icon')){
                    //	thisHeader.prepend('<i class="jarviswidget-icon '+tWidget.data('widget-icon')+'"></i>');
                    //}

                    /**
                     * Add a delete button to the widget header (if set to true).
                     **/
                    if (self.o.customButton === true &&
                        tWidget.data("widget-custombutton") ===
                        undefined &&
                        self.customClass[0].length !== 0) {
                        customBtn =
                            '<a href="javascript:void(0);" class="button-icon jarviswidget-custom-btn"><i class="' +
                            self.customClass[0] +
                            '"></i></a>';
                    } else {
                        customBtn = "";
                    }

                    /**
                     * Add a delete button to the widget header (if set to true).
                     **/
                    if (self.o.deleteButton === true &&
                        tWidget.data("widget-deletebutton") ===
                        undefined) {
                        deleteBtn =
                            '<a href="javascript:void(0);" class="button-icon jarviswidget-delete-btn" rel="tooltip" title="Delete" data-placement="bottom"><i class="' +
                            self.o.deleteClass +
                            '"></i></a>';
                    } else {
                        deleteBtn = "";
                    }

                    /**
                     * Add a delete button to the widget header (if set to true).
                     **/
                    if (self.o.editButton === true && tWidget.data("widget-editbutton") === undefined) {
                        editBtn =
                            '<a href="javascript:void(0);" class="button-icon jarviswidget-edit-btn" rel="tooltip" title="Edit" data-placement="bottom"><i class="' +
                            self.editClass[0] +
                            '"></i></a>';
                    } else {
                        editBtn = "";
                    }

                    /**
                     * Add a delete button to the widget header (if set to true).
                     **/
                    if (self.o.fullscreenButton === true &&
                        tWidget.data("widget-fullscreenbutton") ===
                        undefined) {
                        fullscreenBtn =
                            '<a href="javascript:void(0);" class="button-icon jarviswidget-fullscreen-btn" rel="tooltip" title="Fullscreen" data-placement="bottom"><i class="' +
                            self.fullscreenClass[0] +
                            '"></i></a>';
                    } else {
                        fullscreenBtn = "";
                    }

                    /**
                     * Add a delete button to the widget header (if set to true).
                     **/
                    if (self.o.colorButton === true &&
                        tWidget.data("widget-colorbutton") ===
                        undefined) {
                        widgetcolorBtn =
                            '<a data-toggle="dropdown" class="dropdown-toggle color-box selector" href="javascript:void(0);"></a><ul class="dropdown-menu arrow-box-up-right color-select pull-right"><li><span class="bg-color-green" data-widget-setstyle="jarviswidget-color-green" rel="tooltip" data-placement="left" data-original-title="Green Grass"></span></li><li><span class="bg-color-greenDark" data-widget-setstyle="jarviswidget-color-greenDark" rel="tooltip" data-placement="top" data-original-title="Dark Green"></span></li><li><span class="bg-color-greenLight" data-widget-setstyle="jarviswidget-color-greenLight" rel="tooltip" data-placement="top" data-original-title="Light Green"></span></li><li><span class="bg-color-purple" data-widget-setstyle="jarviswidget-color-purple" rel="tooltip" data-placement="top" data-original-title="Purple"></span></li><li><span class="bg-color-magenta" data-widget-setstyle="jarviswidget-color-magenta" rel="tooltip" data-placement="top" data-original-title="Magenta"></span></li><li><span class="bg-color-pink" data-widget-setstyle="jarviswidget-color-pink" rel="tooltip" data-placement="right" data-original-title="Pink"></span></li><li><span class="bg-color-pinkDark" data-widget-setstyle="jarviswidget-color-pinkDark" rel="tooltip" data-placement="left" data-original-title="Fade Pink"></span></li><li><span class="bg-color-blueLight" data-widget-setstyle="jarviswidget-color-blueLight" rel="tooltip" data-placement="top" data-original-title="Light Blue"></span></li><li><span class="bg-color-teal" data-widget-setstyle="jarviswidget-color-teal" rel="tooltip" data-placement="top" data-original-title="Teal"></span></li><li><span class="bg-color-blue" data-widget-setstyle="jarviswidget-color-blue" rel="tooltip" data-placement="top" data-original-title="Ocean Blue"></span></li><li><span class="bg-color-blueDark" data-widget-setstyle="jarviswidget-color-blueDark" rel="tooltip" data-placement="top" data-original-title="Night Sky"></span></li><li><span class="bg-color-darken" data-widget-setstyle="jarviswidget-color-darken" rel="tooltip" data-placement="right" data-original-title="Night"></span></li><li><span class="bg-color-yellow" data-widget-setstyle="jarviswidget-color-yellow" rel="tooltip" data-placement="left" data-original-title="Day Light"></span></li><li><span class="bg-color-orange" data-widget-setstyle="jarviswidget-color-orange" rel="tooltip" data-placement="bottom" data-original-title="Orange"></span></li><li><span class="bg-color-orangeDark" data-widget-setstyle="jarviswidget-color-orangeDark" rel="tooltip" data-placement="bottom" data-original-title="Dark Orange"></span></li><li><span class="bg-color-red" data-widget-setstyle="jarviswidget-color-red" rel="tooltip" data-placement="bottom" data-original-title="Red Rose"></span></li><li><span class="bg-color-redLight" data-widget-setstyle="jarviswidget-color-redLight" rel="tooltip" data-placement="bottom" data-original-title="Light Red"></span></li><li><span class="bg-color-white" data-widget-setstyle="jarviswidget-color-white" rel="tooltip" data-placement="right" data-original-title="Purity"></span></li><li><a href="javascript:void(0);" class="jarviswidget-remove-colors" data-widget-setstyle="" rel="tooltip" data-placement="bottom" data-original-title="Reset widget color to default">Remove</a></li></ul>';
                        thisHeader.prepend('<div class="widget-toolbar">' + widgetcolorBtn + "</div>");

                    } else {
                        widgetcolorBtn = "";
                    }

                    /**
                     * Add a toggle button to the widget header (if set to true).
                     **/
                    if (self.o.toggleButton === true &&
                        tWidget.data("widget-togglebutton") ===
                        undefined) {
                        if (tWidget.data("widget-collapsed") === true ||
                            tWidget.hasClass(
                                "jarviswidget-collapsed")) {
                            toggleSettings = self.toggleClass[1];
                        } else {
                            toggleSettings = self.toggleClass[0];
                        }
                        toggleBtn =
                            '<a href="javascript:void(0);" class="button-icon jarviswidget-toggle-btn" rel="tooltip" title="Collapse" data-placement="bottom"><i class="' +
                            toggleSettings +
                            '"></i></a>';
                    } else {
                        toggleBtn = "";
                    }

                    /**
                     * Add a refresh button to the widget header (if set to true).
                     **/
                    if (self.o.refreshButton === true &&
                        tWidget.data("widget-refreshbutton") !==
                        false &&
                        tWidget.data("widget-load")) {
                        refreshBtn =
                            '<a href="javascript:void(0);" class="button-icon jarviswidget-refresh-btn" data-loading-text="&nbsp;&nbsp;Loading...&nbsp;" rel="tooltip" title="Refresh" data-placement="bottom"><i class="' +
                            self.o.refreshButtonClass +
                            '"></i></a>';
                    } else {
                        refreshBtn = "";
                    }

                    /**
                     * Set the buttons order.
                     **/
                    var formatButtons = self.o.buttonOrder.replace(/%refresh%/g, refreshBtn)
                        .replace(/%delete%/g, deleteBtn)
                        .replace(/%custom%/g, customBtn)
                        .replace(/%fullscreen%/g, fullscreenBtn)
                        .replace(/%edit%/g, editBtn)
                        .replace(/%toggle%/g, toggleBtn);

                    /**
                     * Add a button wrapper to the header.
                     **/
                    if (refreshBtn !== "" ||
                        deleteBtn !== "" ||
                        customBtn !== "" ||
                        fullscreenBtn !== "" ||
                        editBtn !== "" ||
                        toggleBtn !== "") {
                        thisHeader.prepend('<div class="jarviswidget-ctrls">' +
                            formatButtons +
                            "</div>");
                    }

                    /**
                     * Adding a helper class to all sortable widgets, this will be
                     * used to find the widgets that are sortable, it will skip the widgets
                     * that have the dataset 'widget-sortable="false"' set to false.
                     **/
                    if (self.o.sortable === true && tWidget.data("widget-sortable") === undefined) {
                        tWidget.addClass("jarviswidget-sortable");
                    }

                    /**
                     * If the edit box is present copy the title to the input.
                     **/
                    if (tWidget.find(self.o.editPlaceholder)
                        .length) {
                        tWidget.find(self.o.editPlaceholder)
                            .find("input")
                            .val($.trim(thisHeader.children("h2")
                                .text()));
                    }

                    /**
                     * Prepend the image to the widget header.
                     **/
                    thisHeader.append(
                        '<span class="jarviswidget-loader"><i class="fa fa-refresh fa-spin"></i></span>'
                    );

                    /**
                     * Adding roles to some parts.
                     **/
                    tWidget.attr("role", "widget")
                        .children("div")
                        .attr("role", "content")
                        .prev("header")
                        .attr("role", "heading")
                        .children("div")
                        .attr("role", "menu");
                }
            });

            /**
             * Hide all buttons if option is set to true.
             **/
            if (self.o.buttonsHidden === true) {
                $(self.o.pwCtrls)
                    .hide();
            }

            /* activate all tooltips */
            $(".jarviswidget header [rel=tooltip]")
                .tooltip();

            //******************************************************************//
            //////////////////////////////// AJAX ////////////////////////////////
            //******************************************************************//

            /**
             * Loop all ajax widgets.
             **/
            // $.intervalArr = new Array(); - decleared in app.js
            self.obj.find("[data-widget-load]")
                .each(function() {

                    /**
                     * Variables.
                     **/
                    var thisItem = $(this),
                        thisItemHeader = thisItem.children(),
                        pathToFile = thisItem.data("widget-load"),
                        reloadTime = thisItem.data("widget-refresh") * 1000,
                        ajaxLoader = thisItem.children();

                    if (!thisItem.find(".jarviswidget-ajax-placeholder")
                        .length) {

                        /**
                         * Append a AJAX placeholder.
                         **/
                        thisItem.children("widget-body")
                            .append('<div class="jarviswidget-ajax-placeholder">' +
                                self.o.loadingLabel +
                                "</div>");

                        /**
                         * If widget has a reload time refresh the widget, if the value
                         * has been set to 0 dont reload.
                         **/
                        if (thisItem.data("widget-refresh") > 0) {

                            /**
                             * Load file on start.
                             **/
                            self._loadAjaxFile(thisItem, pathToFile, thisItemHeader);

                            /**
                             * Set an interval to reload the content every XXX seconds.
                             * intervalArr.push(setInterval(intervalOne, 2000)  );
                             **/
                            $.intervalArr.push(setInterval(function() {
                                    self._loadAjaxFile(thisItem, pathToFile, thisItemHeader)
                                },
                                reloadTime));

                        } else {

                            /**
                             * Load the content just once.
                             **/
                            self._loadAjaxFile(thisItem, pathToFile, thisItemHeader);

                        }
                    }
                });

            //******************************************************************//
            ////////////////////////////// SORTABLE //////////////////////////////
            //******************************************************************//

            /**
             * jQuery UI soratble, this allows users to sort the widgets.
             * Notice that this part needs the jquery-ui core to work.
             **/
            if (self.o.sortable === true && jQuery.ui) {
                var sortItem = self.obj.find(self.o.grid + ".sortable-grid")
                    .not("[data-widget-excludegrid]");
                sortItem.sortable({
                    items: sortItem.find(self.o.widgets + ".jarviswidget-sortable"),
                    connectWith: sortItem,
                    placeholder: self.o.placeholderClass,
                    cursor: "move",
                    revert: true,
                    opacity: self.o.opacity,
                    delay: 200,
                    cancel: ".button-icon, #jarviswidget-fullscreen-mode > div",
                    zIndex: 10000,
                    handle: self.o.dragHandle,
                    forcePlaceholderSize: true,
                    forceHelperSize: true,
                    update: function(event, ui) {
                        /* run pre-loader in the widget */
                        self._runLoaderWidget(ui.item.children());
                        /* store the positions of the plugins */
                        self._savePositionWidget();
                        /**
                         * Run the callback function.
                         **/
                        if (typeof self.o.onChange == "function") {
                            self.o.onChange.call(this, ui.item);
                        }
                    }
                });
            }

            //*****************************************************************//
            ////////////////////////// BUTTONS VISIBLE //////////////////////////
            //*****************************************************************//

            /**
             * Show and hide the widget control buttons, the buttons will be
             * visible if the users hover over the widgets header. At default the
             * buttons are always visible.
             **/
            if (self.o.buttonsHidden === true) {

                /**
                 * Show and hide the buttons.
                 **/
                self.widget.children("header")
                    .on("mouseenter." + pluginName,
                        function() {
                            $(this)
                                .children(self.o.pwCtrls)
                                .stop(true, true)
                                .fadeTo(100, 1.0);
                        })
                    .on("mouseleave." + pluginName,
                        function() {
                            $(this)
                                .children(self.o.pwCtrls)
                                .stop(true, true)
                                .fadeTo(100, 0.0);
                        });
            }

            //*****************************************************************//
            ///////////////////////// CLICKEVENTS //////////////////////////
            //*****************************************************************//

            self._clickEvents();

            //*****************************************************************//
            ///////////////////// DELETE LOCAL STORAGE KEYS /////////////////////
            //*****************************************************************//

            if (self.storage.enabled) {
                /**
                 * Delete the settings key.
                 **/
                $(self.o.deleteSettingsKey)
                    .on(clickEvent,
                        this,
                        function(e) {
                            var cleared = confirm(self.o.settingsKeyLabel);
                            if (cleared) {
                                localStorage.removeItem(keySettings);
                            }
                            e.preventDefault();
                        });
                /**
                 * Delete the position key.
                 **/
                $(self.o.deletePositionKey)
                    .on(clickEvent,
                        this,
                        function(e) {
                            var cleared = confirm(self.o.positionKeyLabel);
                            if (cleared) {
                                localStorage.removeItem(keyPosition);
                            }
                            e.preventDefault();
                        });
            }

            initialized = true;
        },

        /**
         * Initialize storage.
         *
         * @param:
         **/
        _initStorage: function(storage) {

            //*****************************************************************//
            //////////////////////// LOCALSTORAGE CHECK /////////////////////////
            //*****************************************************************//

            storage.enabled = storage.enabled &&
                !! function() {
                    var result, uid = +new Date();
                    try {
                        localStorage.setItem(uid, uid);
                        result = localStorage.getItem(uid) == uid;
                        localStorage.removeItem(uid);
                        return result;
                    } catch (e) {
                    }
                }();

            this._loadKeys();

            if (storage.enabled) {

                storage.getKeySettings = localStorage.getItem(storage.keySettings);
                storage.getKeyPosition = localStorage.getItem(storage.keyPosition);

            } // end if

        },

        /**
         * All of the click events.
         *
         * @param:
         **/
        _clickEvents: function() {

            var self = this;

            var headers = self.widget.children("header");

            //*****************************************************************//
            /////////////////////////// TOGGLE WIDGETS //////////////////////////
            //*****************************************************************//

            /**
             * Allow users to toggle the content of the widgets.
             **/
            headers.on(clickEvent,
                ".jarviswidget-toggle-btn",
                function(e) {

                    var tWidget = $(this);
                    var pWidget = tWidget.parents(self.o.widgets);

                    /**
                     * Run function for the indicator image.
                     **/
                    self._runLoaderWidget(tWidget);

                    /**
                     * Change the class and hide/show the widgets content.
                     **/
                    if (pWidget.hasClass("jarviswidget-collapsed")) {
                        tWidget.children()
                            .removeClass(self.toggleClass[1])
                            .addClass(self.toggleClass[0])
                            .parents(self.o.widgets)
                            .removeClass("jarviswidget-collapsed")
                            .children("[role=content]")
                            .slideDown(self.o.toggleSpeed,
                                function() {
                                    self._saveSettingsWidget();
                                });
                    } else {
                        tWidget.children()
                            .removeClass(self.toggleClass[0])
                            .addClass(self.toggleClass[1])
                            .parents(self.o.widgets)
                            .addClass("jarviswidget-collapsed")
                            .children("[role=content]")
                            .slideUp(self.o.toggleSpeed,
                                function() {
                                    self._saveSettingsWidget();
                                });
                    }

                    /**
                     * Run the callback function.
                     **/
                    if (typeof self.o.onToggle == "function") {
                        self.o.onToggle.call(this, pWidget);
                    }

                    e.preventDefault();
                });

            //*****************************************************************//
            ///////////////////////// FULLSCREEN WIDGETS ////////////////////////
            //*****************************************************************//

            /**
             * Set fullscreen height function.
             **/
            function heightFullscreen() {
                if ($("#jarviswidget-fullscreen-mode")
                    .length) {

                    /**
                     * Setting height variables.
                     **/
                    var heightWindow = $(window)
                        .height();
                    var heightHeader = $("#jarviswidget-fullscreen-mode")
                        .children(self.o.widgets)
                        .children("header")
                        .height();

                    /**
                     * Setting the height to the right widget.
                     **/
                    $("#jarviswidget-fullscreen-mode")
                        .children(self.o.widgets)
                        .children("div")
                        .height(heightWindow - heightHeader - 15);
                }
            }

            /**
             * On click go to fullscreen mode.
             **/
            headers.on(clickEvent,
                ".jarviswidget-fullscreen-btn",
                function(e) {

                    var thisWidget = $(this)
                        .parents(self.o.widgets);
                    var thisWidgetContent = thisWidget.children("div");

                    /**
                     * Run function for the indicator image.
                     **/
                    self._runLoaderWidget($(this));

                    /**
                     * Wrap the widget and go fullsize.
                     **/
                    if ($("#jarviswidget-fullscreen-mode")
                        .length) {

                        /**
                         * Remove class from the body.
                         **/
                        $(".nooverflow")
                            .removeClass("nooverflow");

                        /**
                         * Unwrap the widget, remove the height, set the right
                         * fulscreen button back, and show all other buttons.
                         **/
                        thisWidget.unwrap("#jarviswidget-fullscreen-mode")
                            .children("div")
                            .removeAttr("style")
                            .end()
                            .find(".jarviswidget-fullscreen-btn:first")
                            .children()
                            .removeClass(self.fullscreenClass[1])
                            .addClass(self.fullscreenClass[0])
                            .parents(self.pwCtrls)
                            .children("a")
                            .show();

                        /**
                         * Reset collapsed widgets.
                         **/
                        if (thisWidgetContent.hasClass("jarviswidget-visible")) {
                            thisWidgetContent.hide()
                                .removeClass("jarviswidget-visible");
                        }

                    } else {

                        /**
                         * Prevent the body from scrolling.
                         **/
                        $("body")
                            .addClass("nooverflow");

                        /**
                         * Wrap, append it to the body, show the right button
    
                         * and hide all other buttons.
                         **/
                        thisWidget.wrap('<div id="jarviswidget-fullscreen-mode"/>')
                            .parent()
                            .find(".jarviswidget-fullscreen-btn:first")
                            .children()
                            .removeClass(self.fullscreenClass[0])
                            .addClass(self.fullscreenClass[1])
                            .parents(self.pwCtrls)
                            .children("a:not(.jarviswidget-fullscreen-btn)")
                            .hide();

                        /**
                         * Show collapsed widgets.
                         **/
                        if (thisWidgetContent.is(":hidden")) {
                            thisWidgetContent.show()
                                .addClass("jarviswidget-visible");
                        }
                    }

                    /**
                     * Run the set height function.
                     **/
                    heightFullscreen();

                    /**
                     * Run the callback function.
                     **/
                    if (typeof self.o.onFullscreen == "function") {
                        self.o.onFullscreen.call(this, thisWidget);
                    }

                    e.preventDefault();
                });

            /**
             * Run the set fullscreen height function when the screen resizes.
             **/
            $(window)
                .on("resize." + pluginName,
                    function() {

                        /**
                         * Run the set height function.
                         **/
                        heightFullscreen();
                    });

            //*****************************************************************//
            //////////////////////////// EDIT WIDGETS ///////////////////////////
            //*****************************************************************//

            /**
             * Allow users to show/hide a edit box.
             **/
            headers.on(clickEvent,
                ".jarviswidget-edit-btn",
                function(e) {

                    var tWidget = $(this)
                        .parents(self.o.widgets);

                    /**
                     * Run function for the indicator image.
                     **/
                    self._runLoaderWidget($(this));

                    /**
                     * Show/hide the edit box.
                     **/
                    if (tWidget.find(self.o.editPlaceholder)
                        .is(":visible")) {
                        $(this)
                            .children()
                            .removeClass(self.editClass[1])
                            .addClass(self.editClass[0])
                            .parents(self.o.widgets)
                            .find(self.o.editPlaceholder)
                            .slideUp(self.o.editSpeed,
                                function() {
                                    self._saveSettingsWidget();
                                });
                    } else {
                        $(this)
                            .children()
                            .removeClass(self.editClass[0])
                            .addClass(self.editClass[1])
                            .parents(self.o.widgets)
                            .find(self.o.editPlaceholder)
                            .slideDown(self.o.editSpeed);
                    }

                    /**
                     * Run the callback function.
                     **/
                    if (typeof self.o.onEdit == "function") {
                        self.o.onEdit.call(this, tWidget);
                    }

                    e.preventDefault();
                });

            /**
             * Update the widgets title by using the edit input.
             **/
            $(self.o.editPlaceholder)
                .find("input")
                .keyup(function() {
                    $(this)
                        .parents(self.o.widgets)
                        .children("header")
                        .children("h2")
                        .text($(this)
                            .val());
                });

            /**
             * Set a custom style.
             **/
            headers.on(clickEvent,
                "[data-widget-setstyle]",
                function(e) {

                    var val = $(this)
                        .data("widget-setstyle");
                    var styles = "";

                    /**
                     * Get all other styles, in order to remove it.
                     **/
                    $(this)
                        .parents(self.o.editPlaceholder)
                        .find("[data-widget-setstyle]")
                        .each(function() {
                            styles += $(this)
                                .data("widget-setstyle") +
                                " ";
                        });

                    /**
                     * Set the new style.
                     **/
                    $(this)
                        .parents(self.o.widgets)
                        .attr("data-widget-attstyle", "" + val + "")
                        .removeClassPrefix("jarviswidget-color-")
                        .addClass(val);

                    /**
                     * Run function for the indicator image.
                     **/
                    self._runLoaderWidget($(this));

                    /**
                     * Lets save the setings.
                     **/
                    self._saveSettingsWidget();

                    e.preventDefault();
                });

            //*****************************************************************//
            /////////////////////////// CUSTOM ACTION ///////////////////////////
            //*****************************************************************//

            /**
             * Allow users to show/hide a edit box.
             **/
            headers.on(clickEvent,
                ".jarviswidget-custom-btn",
                function(e) {

                    var w = $(this)
                        .parents(self.o.widgets);

                    /**
                     * Run function for the indicator image.
                     **/
                    self._runLoaderWidget($(this));

                    /**
                     * Start and end custom action.
                     **/
                    if ($(this)
                        .children("." + self.customClass[0])
                        .length) {
                        $(this)
                            .children()
                            .removeClass(self.customClass[0])
                            .addClass(self.customClass[1]);

                        /**
                         * Run the callback function.
                         **/
                        if (typeof self.o.customStart == "function") {
                            self.o.customStart.call(this, w);
                        }
                    } else {
                        $(this)
                            .children()
                            .removeClass(self.customClass[1])
                            .addClass(self.customClass[0]);

                        /**
                         * Run the callback function.
                         **/
                        if (typeof self.o.customEnd == "function") {
                            self.o.customEnd.call(this, w);
                        }
                    }

                    /**
                     * Lets save the setings.
                     **/
                    self._saveSettingsWidget();

                    e.preventDefault();
                });

            //*****************************************************************//
            /////////////////////////// DELETE WIDGETS //////////////////////////
            //*****************************************************************//

            /**
             * Allow users to delete the widgets.
             **/
            headers.on(clickEvent,
                ".jarviswidget-delete-btn",
                function(e) {

                    var tWidget = $(this)
                        .parents(self.o.widgets);
                    var removeId = tWidget.attr("id");
                    var widTitle = tWidget.children("header")
                        .children("h2")
                        .text();

                    /**
                     * Delete the widgets with a confirm popup.
                     **/

                    if ($.SmartMessageBox) {

                        $.SmartMessageBox({
                                title: "<i class='fa fa-times' style='color:#ed1c24'></i> " +
                                    self.o.labelDelete +
                                    ' "' +
                                    widTitle +
                                    '"',
                                content: self.o.deleteMsg,
                                buttons: "[No][Yes]"
                            },
                            function(ButtonPressed) {
                                //console.log(ButtonPressed);
                                if (ButtonPressed == "Yes") {
                                    /**
                                     * Run function for the indicator image.
                                     **/
                                    self._runLoaderWidget($(this));

                                    /**
                                     * Delete the right widget.
                                     **/
                                    $("#" + removeId)
                                        .fadeOut(self.o.deleteSpeed,
                                            function() {

                                                $(this)
                                                    .remove();

                                                /**
                                                 * Run the callback function.
                                                 **/
                                                if (typeof self.o.onDelete == "function") {
                                                    self.o.onDelete.call(this, tWidget);
                                                }
                                            });
                                }

                            });

                    } else {

                        /**
                         * Delete the right widget.
                         **/
                        $("#" + removeId)
                            .fadeOut(self.o.deleteSpeed,
                                function() {

                                    $(this)
                                        .remove();

                                    /**
                                     * Run the callback function.
                                     **/
                                    if (typeof self.o.onDelete == "function") {
                                        self.o.onDelete.call(this, tWidget);
                                    }
                                });

                    }

                    e.preventDefault();
                });

            //******************************************************************//
            /////////////////////////// REFRESH BUTTON ///////////////////////////
            //******************************************************************//

            /**
             * Refresh ajax upon clicking refresh link.
             **/
            headers.on(clickEvent,
                ".jarviswidget-refresh-btn",
                function(e) {

                    /**
                     * Variables.
                     **/
                    var rItem = $(this)
                            .parents(self.o.widgets),
                        pathToFile = rItem.data("widget-load"),
                        ajaxLoader = rItem.children(),
                        btn = $(this);

                    /**
                     * Run the ajax function.
                     **/
                    btn.button("loading");
                    ajaxLoader.addClass("widget-body-ajax-loading");
                    setTimeout(function() {
                            btn.button("reset");
                            ajaxLoader.removeClass("widget-body-ajax-loading");
                            self._loadAjaxFile(rItem, pathToFile, ajaxLoader);

                        },
                        1000);

                    e.preventDefault();
                });

            headers = null;
        },

        /**
         * Destroy.
         *
         * @param:
         **/
        destroy: function() {
            var self = this,
                namespace = "." + pluginName,
                sortItem = self.obj.find(self.o.grid + ".sortable-grid").not("[data-widget-excludegrid]");

            sortItem.sortable("destroy");
            self.widget.children("header").off(namespace);
            $(self.o.deleteSettingsKey).off(namespace);
            $(self.o.deletePositionKey).off(namespace);
            $(window).off(namespace);
            self.obj.removeData(pluginName);
        }
    };

    $.fn[pluginName] = function(option) {
        return this.each(function() {
            var $this = $(this);
            var data = $this.data(pluginName);
            if (!data) {
                var options = typeof option == "object" && option;
                $this.data(pluginName, (data = new Plugin(this, options)));
            }
            if (typeof option == "string") {
                data[option]();
            }
        });
    };

    /**
     * Default settings(dont change).
     * You can globally override these options
     * by using $.fn.pluginName.key = 'value';
     **/

    $.fn[pluginName].defaults = {
        grid: "section",
        widgets: ".jarviswidget",
        localStorage: true,
        deleteSettingsKey: "",
        settingsKeyLabel: "Reset settings?",
        deletePositionKey: "",
        positionKeyLabel: "Reset position?",
        sortable: true,
        buttonsHidden: false,
        toggleButton: true,
        toggleClass: "min-10 | plus-10",
        toggleSpeed: 200,
        onToggle: function() {},
        deleteButton: true,
        deleteMsg: "Warning: This action cannot be undone",
        deleteClass: "trashcan-10",
        deleteSpeed: 200,
        onDelete: function() {},
        editButton: true,
        editPlaceholder: ".jarviswidget-editbox",
        editClass: "pencil-10 | delete-10",
        editSpeed: 200,
        onEdit: function() {},
        colorButton: true,
        fullscreenButton: true,
        fullscreenClass: "fullscreen-10 | normalscreen-10",
        fullscreenDiff: 3,
        onFullscreen: function() {},
        customButton: true,
        customClass: "",
        customStart: function() {},
        customEnd: function() {},
        buttonOrder: "%refresh% %delete% %custom% %edit% %fullscreen% %toggle%",
        opacity: 1.0,
        dragHandle: "> header",
        placeholderClass: "jarviswidget-placeholder",
        indicator: true,
        indicatorTime: 600,
        ajax: true,
        loadingLabel: "loading...",
        timestampPlaceholder: ".jarviswidget-timestamp",
        timestampFormat: "Last update: %m%/%d%/%y% %h%:%i%:%s%",
        refreshButton: true,
        refreshButtonClass: "refresh-10",
        labelError: "Sorry but there was a error:",
        labelUpdated: "Last Update:",
        labelRefresh: "Refresh",
        labelDelete: "Delete widget:",
        afterLoad: function() {},
        rtl: false,
        onChange: function() {},
        onSave: function() {},
        ajaxnav: true
    };

    /*
     * REMOVE CSS CLASS WITH PREFIX
     * Description: Remove classes that have given prefix. You have an element with classes
     * 				"widget widget-color-red"
     * Usage: $elem.removeClassPrefix('widget-color-');
     */

    $.fn.removeClassPrefix = function(prefix) {

        this.each(function(i, it) {
            var classes = it.className.split(" ")
                .map(function(item) {
                    return item.indexOf(prefix) === 0 ? "" : item;
                });
            //it.className = classes.join(" ");
            it.className = $.trim(classes.join(" "));

        });

        return this;
    };
})(jQuery, window, document);
